{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lesson 5\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Mean-Variance Optimization of Portfolios "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson5GoalHeaderImage.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.1 Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An investor can take recourse to traditional portfolio construction methods to determine the asset allocation weights.  **Lesson 4 Traditional Methods for Portfolio Construction** discussed two such methods, viz., **Equal weighted portfolio contruction** and **Inverse volatility weighted portfolio construction**.   \n",
    "\n",
    "However, is there a possibility where the **optimal weights**,  that obtains the **maximum return** of a portfolio  for a **minimal risk**, can be determined? In other words, is it possible for an investor to determine the optimal or the best apportionment of capital to assets in the portfolio, so that the investor reaps maximum return for  a minimum risk? Tough question, indeed! But thankfully, the answer is a firm Yes!  \n",
    "  \n",
    "The **Markowitz model** [MAR 52]  built on the **Mean-Variance** framework of asset returns is an elegant solution to this question. Also known as **Mean-Variance Optimization (MVO)**,  the model aims to solve a multi-objective optimization problem subject to basic constraints imposed on the portfolio. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.2 Mean-Variance Optimization Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We briefly recall the return and risk of a portfolio that was discussed in **Lesson 1 Fundamentals of risk and return of a portfolio**.     \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let P be a portfolio comprising assets $A_1, A_2,...A_N$ with weights $W_1, W_2,...W_N$ and $\\mu_1, \\mu_2, ...\\mu_N$ as the asset returns. The portfolio return *r*  determined by a weighted summation of its individual asset returns is given by, "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](Lesson5Eqn5_1.png)\n",
    "<h5 align=\"right\">..........(5.1)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Portfolio risk is the standard deviation of its returns and is given by,"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson5Eqn5_2.png)\n",
    "<h5 align=\"right\">..........(5.2)</h5>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where $\\sigma_{i,j}$ is the variance-covariance matrix of returns. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Mean-Variance Optimization model is given by:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](Lesson5Eqn5_3.png)\n",
    "<h5 align=\"right\">..........(5.3)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The model works on two **objective functions**,  \n",
    "(i)  **to maximize expected portfolio return** and   \n",
    "(ii) **to minimize risk of the portfolio**   \n",
    "It therefore aims to solve a **non-linear bi-objective optimization problem**.     \n",
    "\n",
    "The MVO model incorporates the **basic constraints** of   \n",
    "(i) **the sum of the weights equals 1.**   \n",
    "    This means that  the investor's capital is fully invested in the portfolio and in such a case,  the portfolio is termed as a **fully invested portfolio**.   \n",
    "(ii) **the weights $W_i$ lie between 0 and 1.**   \n",
    "This means that either no capital may be allotted for investment in an asset ($W_i = 0$) or the entire capital may be invested in  an asset ($W_i = 1$) or the capital may be apportioned between assets in the porfolio for weights that range between the interval (0,1).  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.3 Solving the MVO Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "While there are many ways to solve a bi-objective optimization problem, we choose to solve the problem by decomposing it into two three sub-problem models, viz.,   \n",
    "(i)   obtaining the maximal expected return $R^{MaxRetrn}$ of the portfolio,  subject to basic constraints,  \n",
    "(ii)  obtaining the optimal expected return $R^{MinRisk}$ corresponding to the minimum risk portfolio,  subject to basic constraints, and finally,   \n",
    "(iii) obtaining the optimal weights of the portfolio sets that minimize risk and whose returns R lie between $R^{MinRisk}$ and  $R^{MaxRetrn}$, (i.e.)  $R^{MinRisk} \\le R \\le R^{MaxRetrn}$, subject to basic constraints.    \n",
    "\n",
    "The optimal portfolio set is referred to as the **efficient set**.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3.1  Obtaining the Maximal Expected Return of the Portfolio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The mathematical model for this sub-problem is given by, "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson5Eqn5_4.png)\n",
    "<h5 align=\"right\">..........(5.4)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The optimal weights $W_{i}^{Optimal}$ obtained by solving (5.4) is used to compute $R^{MaxRetrn} = \\sum{\\left(W_{i}^{Optimal}.\\mu_i\\right)}$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python function **MaximizeReturns** employs scipy and NumPy to obtain the optimal weights. Since the problem model is linear, **linprog** function from the package scipy.optimize is invoked to execute **linear programming** to solve the problem model.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "#function obtains maximal return portfolio using linear programming\n",
    "\n",
    "def MaximizeReturns(MeanReturns, PortfolioSize):\n",
    "    \n",
    "    #dependencies\n",
    "    from scipy.optimize import linprog\n",
    "    import numpy as np\n",
    "    \n",
    "    c = (np.multiply(-1, MeanReturns))\n",
    "    A = np.ones([PortfolioSize,1]).T\n",
    "    b=[1]\n",
    "    res = linprog(c, A_ub = A, b_ub = b, bounds = (0,1), method = 'simplex') \n",
    "    \n",
    "    return res"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3.2  Obtaining the Optimal Expected Return of a Minimum Risk Portfolio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The mathematical model for this sub-problem is given by"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](Lesson5Eqn5_5.png)\n",
    "<h5 align=\"right\">..........(5.5)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The optimal weights $W_{i}^{Optimal}$ obtained by solving (5.5) is used to compute $R^{MinRisk} = \\sum{\\left(W_{i}^{Optimal}.\\mu_i\\right)}$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python function **MinimizeRisk** employs scipy.optimize and NumPy to obtain the optimal weights.  \n",
    "\n",
    "Functions  <b>f</b> and **constraintEq** describe the non-linear objective function and the fully invested constraint described in (5.5),  respectively. **optimize.minimize** function executes minimization of scalar functions with one or more variables. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "#function obtains minimal risk portfolio \n",
    "\n",
    "#dependencies\n",
    "import numpy as np\n",
    "from scipy import optimize \n",
    "\n",
    "def MinimizeRisk(CovarReturns, PortfolioSize):\n",
    "    \n",
    "    def  f(x, CovarReturns):\n",
    "        func = np.matmul(np.matmul(x, CovarReturns), x.T) \n",
    "        return func\n",
    "\n",
    "    def constraintEq(x):\n",
    "        A=np.ones(x.shape)\n",
    "        b=1\n",
    "        constraintVal = np.matmul(A,x.T)-b \n",
    "        return constraintVal\n",
    "    \n",
    "    xinit=np.repeat(0.1, PortfolioSize)\n",
    "    cons = ({'type': 'eq', 'fun':constraintEq})\n",
    "    lb = 0\n",
    "    ub = 1\n",
    "    bnds = tuple([(lb,ub) for x in xinit])\n",
    "\n",
    "    opt = optimize.minimize (f, x0 = xinit, args = (CovarReturns),  bounds = bnds, \\\n",
    "                             constraints = cons, tol = 10**-3)\n",
    "    \n",
    "    return opt\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3.3   Obtaining the Optimal Weights  for Minimum Risk and  Maximum Return Portfolios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The mathematical model for this sub-problem is defined as follows, where for each R, $R^{MinRisk} \\le R \\le R^{MaxRetrn}$, the problem model is repeatedly solved to arrive at the optimal weight sets,  each of which determines a portfolio that minimizes risk and maximizes return.  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](Lesson5Eqn5_6.png)\n",
    "<h5 align=\"right\">..........(5.6)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python function **MinimizeRiskConstr** employs scipy and NumPy to obtain the optimal weight sets. Functions <b>f</b>, **constraintEq** and **constraintIneq** describe the objective function, equality constraint and inequality constraint of (5.6). Function **optimize.minimize** uses the Trust-Region Constrained algorithm (**method = 'trust-constr'**) to solve the constrained optimization problem with both equality and inequality constraints.   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "#function obtains Minimal risk and Maximum return portfolios\n",
    "\n",
    "#dependencies\n",
    "import numpy as np\n",
    "from scipy import optimize \n",
    "\n",
    "def MinimizeRiskConstr(MeanReturns, CovarReturns, PortfolioSize, R):\n",
    "    \n",
    "    def  f(x,CovarReturns):\n",
    "         \n",
    "        func = np.matmul(np.matmul(x,CovarReturns ), x.T)\n",
    "        return func\n",
    "\n",
    "    def constraintEq(x):\n",
    "        AEq=np.ones(x.shape)\n",
    "        bEq=1\n",
    "        EqconstraintVal = np.matmul(AEq,x.T)-bEq \n",
    "        return EqconstraintVal\n",
    "    \n",
    "    def constraintIneq(x, MeanReturns, R):\n",
    "        AIneq = np.array(MeanReturns)\n",
    "        bIneq = R\n",
    "        IneqconstraintVal = np.matmul(AIneq,x.T) - bIneq\n",
    "        return IneqconstraintVal\n",
    "    \n",
    "\n",
    "    xinit=np.repeat(0.1, PortfolioSize)\n",
    "    cons = ({'type': 'eq', 'fun':constraintEq},\n",
    "            {'type':'ineq', 'fun':constraintIneq, 'args':(MeanReturns,R) })\n",
    "    lb = 0\n",
    "    ub = 1\n",
    "    bnds = tuple([(lb,ub) for x in xinit])\n",
    "\n",
    "    opt = optimize.minimize (f, args = (CovarReturns), method ='trust-constr',  \\\n",
    "                        x0 = xinit,   bounds = bnds, constraints = cons, tol = 10**-3)\n",
    "    \n",
    "    return  opt\n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.3  Case Study"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us suppose that an investor decides to invest in a $k$-portfolio ($k$-portfolio 1) comprising the  following  Dow stocks. (Selection of $k$ portfolio 1, is detailed in **Lesson 3 Heuristic Portfolio Selection**)   \n",
    "\n",
    "**𝑘-portfolio 1**:  \n",
    "\n",
    "{Coca-Cola (KO), United Health (UNH), Walt Disney (DIS), IBM (IBM), Cisco (CSCO), JPMorgan Chase (JPM), Goldman Sachs (GS), Walgreens Boots Alliance (WBA), Apple (AAPL), Home Depot (HD), American Express (AXP), McDonald's (MCD), Merck (MRK), Boeing (BA), Caterpillar (CAT)}     \n",
    "\n",
    "The investor desires to explore the optimal portfolio sets that yield maximum expected portfolio return and  minimum risk. The objective is to know the optimal weights given an expected return or a desired risk.  \n",
    "\n",
    "To apply the MVO model, the historical data set for the $k$-portfolio ( DJIA index: April 11 2014 to April 11, 2019) is cleaned and kept fit for use by the three stage process of optimization discussed in Sec. 5.2. (**Lesson 2 Some glimpses of Financial Data Wrangling** discusses aspects of data cleaning or data wrangling)  \n",
    "\n",
    "The following Python code reads the dataset concerned, computes the stock returns using the Python function **StockReturnsComputing** and obtains the mean returns and the variance-covariance matrix of returns. (Refer **Lesson 1 Fundamentals of Risk and Return of a Portfolio** to know about risk and return of a portfolio). \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "# function computes asset returns \n",
    "def StockReturnsComputing(StockPrice, Rows, Columns):\n",
    "    \n",
    "    import numpy as np\n",
    "    \n",
    "    StockReturn = np.zeros([Rows-1, Columns])\n",
    "    for j in range(Columns):        # j: Assets\n",
    "        for i in range(Rows-1):     # i: Daily Prices\n",
    "            StockReturn[i,j]=((StockPrice[i+1, j]-StockPrice[i,j])/StockPrice[i,j])* 100\n",
    "\n",
    "    return StockReturn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['AAPL', 'AXP', 'BA', 'CAT', 'CSCO', 'DIS', 'GS', 'HD', 'IBM', 'JPM', 'KO', 'MCD', 'MRK', 'UNH', 'WBA']\n",
      "Mean returns of assets in k-portfolio 1\n",
      " [ 0.09   0.029  0.1    0.039  0.081  0.04   0.033  0.085 -0.016  0.06\n",
      "  0.019  0.057  0.036  0.095 -0.002]\n",
      "Variance-Covariance matrix of returns\n",
      " [[2.375 0.672 0.962 1.042 0.999 0.68  0.954 0.726 0.709 0.825 0.306 0.458\n",
      "  0.534 0.774 0.697]\n",
      " [0.672 1.648 0.8   0.95  0.7   0.569 1.065 0.658 0.663 1.001 0.307 0.35\n",
      "  0.556 0.718 0.667]\n",
      " [0.962 0.8   2.288 1.31  0.89  0.716 1.066 0.747 0.777 0.977 0.381 0.472\n",
      "  0.578 0.745 0.679]\n",
      " [1.042 0.95  1.31  2.733 1.041 0.688 1.321 0.796 0.885 1.169 0.358 0.455\n",
      "  0.616 0.72  0.681]\n",
      " [0.999 0.7   0.89  1.041 1.789 0.713 0.927 0.724 0.817 0.909 0.362 0.477\n",
      "  0.647 0.656 0.707]\n",
      " [0.68  0.569 0.716 0.688 0.713 1.35  0.773 0.586 0.574 0.717 0.302 0.368\n",
      "  0.466 0.557 0.631]\n",
      " [0.954 1.065 1.066 1.321 0.927 0.773 2.114 0.795 0.803 1.554 0.303 0.467\n",
      "  0.705 0.82  0.819]\n",
      " [0.726 0.658 0.747 0.796 0.724 0.586 0.795 1.39  0.619 0.753 0.343 0.472\n",
      "  0.487 0.659 0.689]\n",
      " [0.709 0.663 0.777 0.885 0.817 0.574 0.803 0.619 1.632 0.767 0.372 0.391\n",
      "  0.576 0.564 0.534]\n",
      " [0.825 1.001 0.977 1.169 0.909 0.717 1.554 0.753 0.767 1.702 0.324 0.483\n",
      "  0.675 0.761 0.717]\n",
      " [0.306 0.307 0.381 0.358 0.362 0.302 0.303 0.343 0.372 0.324 0.806 0.36\n",
      "  0.384 0.31  0.355]\n",
      " [0.458 0.35  0.472 0.455 0.477 0.368 0.467 0.472 0.391 0.483 0.36  1.086\n",
      "  0.402 0.43  0.433]\n",
      " [0.534 0.556 0.578 0.616 0.647 0.466 0.705 0.487 0.576 0.675 0.384 0.402\n",
      "  1.504 0.615 0.64 ]\n",
      " [0.774 0.718 0.745 0.72  0.656 0.557 0.82  0.659 0.564 0.761 0.31  0.43\n",
      "  0.615 1.722 0.78 ]\n",
      " [0.697 0.667 0.679 0.681 0.707 0.631 0.819 0.689 0.534 0.717 0.355 0.433\n",
      "  0.64  0.78  2.554]]\n"
     ]
    }
   ],
   "source": [
    "# Obtain optimal portfolio sets that maximize return and minimize risk\n",
    "\n",
    "#Dependencies\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "\n",
    "#input k-portfolio 1 dataset comprising 15 stocks\n",
    "StockFileName = 'DJIA_Apr112014_Apr112019_kpf1.csv'\n",
    "\n",
    "Rows = 1259  #excluding header\n",
    "Columns = 15  #excluding date\n",
    "portfolioSize = Columns #set portfolio size\n",
    "\n",
    "#read stock prices in a dataframe\n",
    "df = pd.read_csv(StockFileName,  nrows= Rows)\n",
    "\n",
    "#extract asset labels\n",
    "assetLabels = df.columns[1:Columns+1].tolist()\n",
    "print(assetLabels)\n",
    "\n",
    "#extract asset prices\n",
    "StockData = df.iloc[0:, 1:]\n",
    "\n",
    "\n",
    "#compute asset returns\n",
    "arStockPrices = np.asarray(StockData)\n",
    "[Rows, Cols]=arStockPrices.shape\n",
    "arReturns = StockReturnsComputing(arStockPrices, Rows, Cols)\n",
    "\n",
    "\n",
    "#compute mean returns and variance covariance matrix of returns\n",
    "meanReturns = np.mean(arReturns, axis = 0)\n",
    "covReturns = np.cov(arReturns, rowvar=False)\n",
    "\n",
    "#set precision for printing results\n",
    "np.set_printoptions(precision=3, suppress = True)\n",
    "\n",
    "#display mean returns and variance-covariance matrix of returns\n",
    "print('Mean returns of assets in k-portfolio 1\\n', meanReturns)\n",
    "print('Variance-Covariance matrix of returns\\n', covReturns)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As the first stage to executing the MVO, the mathematical model discussed in Sec. 5.3.1 is applied to the dataset concerned and the maximum expected portfolio return $R^{MaxRetrn}$ is obtained. The following Python code shows the invocation of function **MaximizeReturns** to arrive at the maximum return. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Maximal Expected Portfolio Return:    0.0997\n"
     ]
    }
   ],
   "source": [
    "#Maximal expected portfolio return computation for the k-portfolio\n",
    "result1 = MaximizeReturns(meanReturns, portfolioSize)\n",
    "maxReturnWeights = result1.x\n",
    "maxExpPortfolioReturn = np.matmul(meanReturns.T, maxReturnWeights)\n",
    "print(\"Maximal Expected Portfolio Return:   %7.4f\" % maxExpPortfolioReturn )\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the second stage, the mathematical model discussed in Sec. 5.3.2 is applied to the dataset and $R^{MinRisk}$,  the expected portfolio return corresponding to the minimum risk is determined. The following Python code shows the invocation of function **MinimizeRisk** to arrive at the return corresponding to minimum risk.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Expected Return of Minimum Risk Portfolio:   0.0361\n"
     ]
    }
   ],
   "source": [
    "#expected portfolio return computation for the minimum risk k-portfolio \n",
    "result2 = MinimizeRisk(covReturns, portfolioSize)\n",
    "minRiskWeights = result2.x\n",
    "minRiskExpPortfolioReturn = np.matmul(meanReturns.T, minRiskWeights)\n",
    "print(\"Expected Return of Minimum Risk Portfolio:  %7.4f\" % minRiskExpPortfolioReturn)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the third stage, the mathematical model discussed in Sec. 5.3.3 is applied,  employing function **MinimizeRiskConstr**. The following Python code shows the repeated invocation of the function controlled by a **while** loop that varies from **low** to **high** in steps of **increment = 0.001**. Here **low** and **high** denote $R^{MinRisk}$ and $R^{MaxReturn}$ respectively. The loop therefore executes (5.6) repeatedly varying R as defined by $R^{MinRisk} \\le R \\le R^{MaxRetrn}$.   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Size of the  efficient set: (64, 15)\n",
      "Optimal weights of the efficient set portfolios: \n",
      " [[ 0.028  0.039  0.023  0.017  0.026  0.103  0.017  0.05   0.032  0.021\n",
      "   0.319  0.192  0.062  0.047  0.025]\n",
      " [ 0.028  0.039  0.023  0.017  0.026  0.108  0.017  0.051  0.032  0.022\n",
      "   0.311  0.192  0.063  0.047  0.025]\n",
      " [ 0.029  0.039  0.024  0.017  0.027  0.108  0.017  0.052  0.031  0.022\n",
      "   0.309  0.192  0.062  0.048  0.024]\n",
      " [ 0.03   0.039  0.025  0.017  0.027  0.107  0.017  0.053  0.03   0.022\n",
      "   0.306  0.192  0.062  0.049  0.024]\n",
      " [ 0.031  0.038  0.024  0.016  0.028  0.086  0.016  0.059  0.028  0.022\n",
      "   0.316  0.197  0.06   0.056  0.023]\n",
      " [ 0.033  0.039  0.027  0.017  0.029  0.103  0.017  0.06   0.028  0.023\n",
      "   0.294  0.185  0.064  0.056  0.023]\n",
      " [ 0.034  0.039  0.028  0.017  0.03   0.102  0.017  0.063  0.027  0.023\n",
      "   0.29   0.184  0.064  0.059  0.023]\n",
      " [ 0.035  0.038  0.03   0.017  0.031  0.101  0.017  0.066  0.026  0.024\n",
      "   0.285  0.183  0.064  0.062  0.022]\n",
      " [ 0.036  0.038  0.031  0.018  0.033  0.099  0.017  0.069  0.025  0.024\n",
      "   0.277  0.184  0.062  0.065  0.022]\n",
      " [ 0.039  0.034  0.034  0.017  0.036  0.058  0.018  0.069  0.023  0.026\n",
      "   0.298  0.205  0.052  0.071  0.021]\n",
      " [ 0.04   0.033  0.036  0.017  0.037  0.056  0.017  0.072  0.022  0.026\n",
      "   0.295  0.203  0.051  0.075  0.021]\n",
      " [ 0.041  0.032  0.037  0.017  0.038  0.055  0.017  0.075  0.02   0.026\n",
      "   0.291  0.202  0.05   0.079  0.02 ]\n",
      " [ 0.05   0.039  0.047  0.026  0.048  0.053  0.026  0.07   0.027  0.036\n",
      "   0.242  0.179  0.054  0.073  0.028]\n",
      " [ 0.052  0.038  0.048  0.026  0.049  0.051  0.026  0.072  0.026  0.037\n",
      "   0.24   0.179  0.053  0.076  0.028]\n",
      " [ 0.052  0.038  0.049  0.026  0.049  0.05   0.026  0.073  0.025  0.037\n",
      "   0.24   0.179  0.053  0.077  0.027]\n",
      " [ 0.049  0.027  0.047  0.016  0.046  0.044  0.016  0.082  0.015  0.028\n",
      "   0.276  0.202  0.044  0.092  0.016]\n",
      " [ 0.053  0.025  0.051  0.016  0.049  0.04   0.016  0.083  0.014  0.029\n",
      "   0.273  0.202  0.041  0.095  0.015]\n",
      " [ 0.056  0.024  0.055  0.016  0.052  0.036  0.015  0.084  0.012  0.03\n",
      "   0.268  0.202  0.039  0.097  0.014]\n",
      " [ 0.059  0.022  0.059  0.016  0.055  0.032  0.015  0.084  0.011  0.031\n",
      "   0.264  0.201  0.036  0.1    0.013]\n",
      " [ 0.063  0.021  0.064  0.015  0.059  0.028  0.015  0.085  0.01   0.032\n",
      "   0.259  0.201  0.034  0.102  0.012]\n",
      " [ 0.066  0.019  0.068  0.015  0.062  0.025  0.015  0.086  0.008  0.033\n",
      "   0.254  0.2    0.032  0.105  0.011]\n",
      " [ 0.069  0.018  0.071  0.015  0.064  0.022  0.015  0.087  0.007  0.033\n",
      "   0.25   0.2    0.03   0.107  0.011]\n",
      " [ 0.069  0.017  0.072  0.015  0.065  0.021  0.015  0.088  0.007  0.033\n",
      "   0.251  0.201  0.029  0.108  0.01 ]\n",
      " [ 0.068  0.016  0.076  0.01   0.064  0.025  0.01   0.103  0.007  0.024\n",
      "   0.237  0.201  0.028  0.121  0.009]\n",
      " [ 0.071  0.015  0.08   0.009  0.068  0.023  0.009  0.103  0.007  0.023\n",
      "   0.232  0.201  0.025  0.126  0.008]\n",
      " [ 0.066  0.015  0.083  0.01   0.072  0.021  0.01   0.111  0.007  0.025\n",
      "   0.219  0.198  0.024  0.132  0.009]\n",
      " [ 0.071  0.013  0.093  0.009  0.078  0.019  0.009  0.108  0.007  0.024\n",
      "   0.214  0.197  0.02   0.129  0.008]\n",
      " [ 0.067  0.012  0.079  0.009  0.069  0.016  0.009  0.125  0.006  0.025\n",
      "   0.207  0.197  0.022  0.153  0.007]\n",
      " [ 0.069  0.01   0.082  0.008  0.072  0.013  0.008  0.127  0.005  0.025\n",
      "   0.202  0.197  0.019  0.157  0.006]\n",
      " [ 0.069  0.01   0.083  0.007  0.073  0.012  0.007  0.128  0.004  0.024\n",
      "   0.202  0.198  0.018  0.159  0.005]\n",
      " [ 0.07   0.009  0.084  0.007  0.073  0.011  0.007  0.129  0.004  0.024\n",
      "   0.202  0.199  0.017  0.16   0.005]\n",
      " [ 0.066  0.013  0.086  0.008  0.072  0.029  0.007  0.148  0.006  0.017\n",
      "   0.144  0.191  0.029  0.177  0.006]\n",
      " [ 0.068  0.013  0.09   0.007  0.074  0.027  0.007  0.151  0.006  0.017\n",
      "   0.135  0.19   0.027  0.183  0.006]\n",
      " [ 0.065  0.012  0.09   0.007  0.073  0.025  0.007  0.161  0.006  0.017\n",
      "   0.123  0.194  0.025  0.189  0.006]\n",
      " [ 0.067  0.012  0.094  0.007  0.076  0.024  0.007  0.163  0.005  0.016\n",
      "   0.114  0.194  0.023  0.193  0.006]\n",
      " [ 0.068  0.011  0.098  0.007  0.078  0.022  0.007  0.166  0.005  0.016\n",
      "   0.105  0.193  0.021  0.199  0.006]\n",
      " [ 0.071  0.011  0.106  0.007  0.086  0.021  0.007  0.162  0.005  0.016\n",
      "   0.099  0.184  0.018  0.202  0.005]\n",
      " [ 0.077  0.008  0.11   0.005  0.088  0.011  0.005  0.164  0.004  0.011\n",
      "   0.107  0.191  0.01   0.204  0.005]\n",
      " [ 0.073  0.009  0.117  0.007  0.083  0.015  0.007  0.179  0.005  0.016\n",
      "   0.079  0.184  0.014  0.205  0.005]\n",
      " [ 0.074  0.009  0.121  0.007  0.085  0.015  0.007  0.183  0.005  0.017\n",
      "   0.067  0.181  0.014  0.209  0.005]\n",
      " [ 0.075  0.009  0.125  0.007  0.086  0.015  0.007  0.188  0.005  0.017\n",
      "   0.055  0.179  0.014  0.214  0.005]\n",
      " [ 0.075  0.009  0.129  0.007  0.088  0.014  0.007  0.191  0.005  0.017\n",
      "   0.046  0.177  0.014  0.217  0.005]\n",
      " [ 0.075  0.008  0.13   0.006  0.088  0.014  0.006  0.193  0.004  0.016\n",
      "   0.045  0.177  0.013  0.218  0.005]\n",
      " [ 0.078  0.008  0.138  0.006  0.084  0.013  0.006  0.201  0.005  0.016\n",
      "   0.021  0.178  0.013  0.227  0.005]\n",
      " [ 0.08   0.008  0.144  0.006  0.085  0.012  0.006  0.204  0.004  0.015\n",
      "   0.011  0.175  0.012  0.231  0.005]\n",
      " [ 0.082  0.008  0.15   0.006  0.085  0.012  0.006  0.207  0.004  0.015\n",
      "   0.001  0.173  0.011  0.235  0.005]\n",
      " [ 0.081  0.004  0.156  0.004  0.083  0.008  0.004  0.218  0.002  0.009\n",
      "   0.015  0.164  0.008  0.242  0.002]\n",
      " [ 0.086  0.003  0.159  0.004  0.079  0.006  0.003  0.223  0.002  0.008\n",
      "   0.014  0.15   0.007  0.253  0.002]\n",
      " [ 0.085  0.002  0.164  0.003  0.076  0.003  0.003  0.221  0.001  0.006\n",
      "   0.003  0.171  0.002  0.259  0.001]\n",
      " [ 0.086  0.002  0.165  0.002  0.076  0.002  0.002  0.222  0.001  0.005\n",
      "   0.003  0.172  0.002  0.26   0.001]\n",
      " [ 0.088  0.002  0.177  0.003  0.072  0.003  0.003  0.233  0.001  0.006\n",
      "   0.003  0.117  0.003  0.288  0.001]\n",
      " [ 0.091  0.002  0.186  0.003  0.07   0.003  0.003  0.235  0.001  0.006\n",
      "   0.003  0.093  0.003  0.301  0.001]\n",
      " [ 0.097  0.003  0.195  0.003  0.064  0.004  0.003  0.248  0.001  0.006\n",
      "   0.003  0.058  0.004  0.309  0.002]\n",
      " [ 0.109  0.003  0.207  0.003  0.059  0.004  0.003  0.242  0.001  0.006\n",
      "   0.003  0.038  0.004  0.317  0.002]\n",
      " [ 0.119  0.002  0.222  0.003  0.038  0.003  0.002  0.241  0.001  0.006\n",
      "   0.003  0.024  0.003  0.331  0.001]\n",
      " [ 0.112  0.002  0.24   0.002  0.038  0.003  0.002  0.236  0.001  0.005\n",
      "   0.003  0.007  0.003  0.344  0.001]\n",
      " [ 0.091  0.001  0.247  0.001  0.022  0.001  0.001  0.264  0.001  0.002\n",
      "   0.001  0.004  0.001  0.361  0.001]\n",
      " [ 0.096  0.001  0.301  0.001  0.018  0.002  0.001  0.174  0.001  0.003\n",
      "   0.001  0.004  0.002  0.394  0.001]\n",
      " [ 0.098  0.     0.315  0.     0.006  0.001  0.     0.168  0.     0.001\n",
      "   0.     0.001  0.001  0.407  0.   ]\n",
      " [ 0.088  0.001  0.382  0.001  0.012  0.001  0.001  0.067  0.     0.001\n",
      "   0.001  0.003  0.001  0.44   0.001]\n",
      " [ 0.062  0.001  0.433  0.001  0.006  0.001  0.001  0.031  0.     0.001\n",
      "   0.001  0.002  0.001  0.46   0.   ]\n",
      " [ 0.048  0.     0.461  0.     0.002  0.     0.     0.027 -0.    -0.\n",
      "   0.    -0.     0.     0.461  0.   ]\n",
      " [ 0.045 -0.     0.467 -0.     0.001 -0.    -0.     0.026 -0.001 -0.\n",
      "  -0.    -0.001 -0.     0.464 -0.   ]\n",
      " [ 0.006 -0.     0.642  0.     0.     0.    -0.    -0.    -0.    -0.\n",
      "  -0.    -0.001 -0.     0.355 -0.   ]]\n",
      "Annualized Risk and Return of the efficient set portfolios: \n",
      " [[11.571  9.049]\n",
      " [11.585  9.3  ]\n",
      " [11.592  9.551]\n",
      " [11.599  9.802]\n",
      " [11.591 10.053]\n",
      " [11.641 10.304]\n",
      " [11.656 10.555]\n",
      " [11.675 10.806]\n",
      " [11.701 11.057]\n",
      " [11.706 11.308]\n",
      " [11.725 11.559]\n",
      " [11.743 11.81 ]\n",
      " [11.991 12.061]\n",
      " [12.013 12.312]\n",
      " [12.023 12.563]\n",
      " [11.86  12.814]\n",
      " [11.905 13.065]\n",
      " [11.953 13.316]\n",
      " [12.004 13.567]\n",
      " [12.056 13.818]\n",
      " [12.11  14.069]\n",
      " [12.161 14.32 ]\n",
      " [12.174 14.571]\n",
      " [12.201 14.822]\n",
      " [12.258 15.073]\n",
      " [12.339 15.324]\n",
      " [12.413 15.575]\n",
      " [12.427 15.826]\n",
      " [12.487 16.077]\n",
      " [12.509 16.328]\n",
      " [12.522 16.579]\n",
      " [12.75  16.83 ]\n",
      " [12.837 17.081]\n",
      " [12.913 17.332]\n",
      " [13.003 17.583]\n",
      " [13.096 17.834]\n",
      " [13.206 18.085]\n",
      " [13.239 18.336]\n",
      " [13.41  18.587]\n",
      " [13.525 18.838]\n",
      " [13.643 19.089]\n",
      " [13.741 19.34 ]\n",
      " [13.765 19.591]\n",
      " [13.979 19.842]\n",
      " [14.1   20.093]\n",
      " [14.223 20.344]\n",
      " [14.229 20.595]\n",
      " [14.354 20.846]\n",
      " [14.412 21.097]\n",
      " [14.439 21.348]\n",
      " [14.775 21.599]\n",
      " [14.969 21.85 ]\n",
      " [15.212 22.101]\n",
      " [15.426 22.352]\n",
      " [15.647 22.603]\n",
      " [15.866 22.854]\n",
      " [15.982 23.105]\n",
      " [16.396 23.356]\n",
      " [16.593 23.607]\n",
      " [17.243 23.858]\n",
      " [17.767 24.109]\n",
      " [18.016 24.36 ]\n",
      " [18.097 24.611]\n",
      " [19.449 24.862]]\n"
     ]
    }
   ],
   "source": [
    "#compute efficient set for the maximum return and minimum risk portfolios\n",
    "increment = 0.001\n",
    "low = minRiskExpPortfolioReturn\n",
    "high = maxExpPortfolioReturn\n",
    "\n",
    "#initialize optimal weight set and risk-return point set\n",
    "xOptimal =[]\n",
    "minRiskPoint = []\n",
    "expPortfolioReturnPoint =[]\n",
    "\n",
    "#repeated execution of function MinimizeRiskConstr to determine the efficient set \n",
    "while (low < high):\n",
    "    \n",
    "    result3 = MinimizeRiskConstr(meanReturns, covReturns, portfolioSize, low)\n",
    "    xOptimal.append(result3.x)\n",
    "    expPortfolioReturnPoint.append(low)\n",
    "    low = low+increment\n",
    "    \n",
    "#gather optimal weight set    \n",
    "xOptimalArray = np.array(xOptimal)\n",
    "\n",
    "#obtain annualized risk for the efficient set portfolios \n",
    "#for trading days = 251\n",
    "minRiskPoint = np.diagonal(np.matmul((np.matmul(xOptimalArray,covReturns)),\\\n",
    "                                     np.transpose(xOptimalArray)))\n",
    "riskPoint =   np.sqrt(minRiskPoint*251) \n",
    "\n",
    "#obtain expected portfolio annualized return for the \n",
    "#efficient set portfolios, for trading days = 251\n",
    "retPoint = 251*np.array(expPortfolioReturnPoint) \n",
    "\n",
    "#display efficient set portfolio parameters\n",
    "print(\"Size of the  efficient set:\", xOptimalArray.shape )\n",
    "print(\"Optimal weights of the efficient set portfolios: \\n\", xOptimalArray)\n",
    "print(\"Annualized Risk and Return of the efficient set portfolios: \\n\", \\\n",
    "                                                np.c_[riskPoint, retPoint])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The efficient set comprises 64 different optimal portfolios. Each of the optimal weight sets can be seen to satisfy all the constraints imposed on them. The optimal weight sets and the annualized risk(%) and return (%) of each of the optimal portfolios,  are now available to the investor for making prudent decisions on the portfolios.  \n",
    "\n",
    "To get back to the investor's objective, if a risk seeking investor aspires to get an annual return of *y*% mindless of the risk involved, then the efficient set allows selecting that portfolio whose risk-return point is [x%, y%] for some x% risk. The corresponding optimal weight set indicates how the investor should apportion the capital on the various assets comprising the $k$-portfolio, to reap the return desired.  \n",
    "\n",
    "In contrast, a risk-averse investor who is too concerned about the risk and hence fixes a risk of x%,  can also get to know about the corresponding return (y%) that the portfolio will fetch for that risk, besides knowing about the  optimal weights that are  required for making such an investment.   \n",
    "  \n",
    " The efficient set therefore provides a gamut of optimal investment decisions to suit the investor's risk appetite.   \n",
    "\n",
    "**Example**  \n",
    "\n",
    "To keep it simple, let us consider a risk averse investor who desires to invest in the aforementioned $k$-portfolio of Dow stocks, with the lowest risk possible.  The efficient set lists the pair [11.571  9.049]  which is the first pair in the efficient set output, offering the lowest annualized risk of 11.571%. If the investor agrees to this risk, then the investor can expect an   annual return of 9.049%. The optimal weights that will effect this are as follows:\n",
    "   [0.028  0.039  0.023  0.017  0.026  0.103  0.017  0.05   0.032  0.021\n",
    "   0.319  0.192  0.062  0.047  0.025].   \n",
    "   \n",
    "To elaborate further, if the investor owns a capital of USD10000,  to gain an annual expected return of 9.049% holding an annualized risk of 11.571%, the investor will have to allot  the capital to the assets in the $k$-portfolio, in the following manner:\n",
    "   \n",
    "['AAPL', 2.8%],  ['AXP', 3.9%],   ['BA', 2.3%],  ['CAT', 1.7%],  ['CSCO', 2.6%],  ['DIS', 10.3%],   ['GS', 1.7%],    ['HD', 5%],  ['IBM', 3.2%],  ['JPM', 2.1%],  ['KO', 31.9%],    ['MCD', 19.2%],  ['MRK', 6.2%], ['UNH', 4.7%],  ['WBA', 2.5%]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.4  Efficient Frontier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The efficient set obtained by the Mean-Variance Optimization model can be graphically represented by what is called an **efficient frontier**. An efficient frontier is a **risk-return tradeoff graph**, which describes a set of optimal portfolios that yield the highest expected  portfolio return for a  defined level of risk or the lowest possible risk for a  defined level of expected portfolio return. It graphs the optimal structure of the portfolio which yields the maximum expected return for a given level of risk or vice-versa.   \n",
    "\n",
    "Portfolio optimization  strives to build portfolios which are on the efficient frontier and not below it, for these are sub-optimal. The set of all optimal portfolios that lie on the efficient frontier, in other words,  those portfolios that generate the largest return for a given level of risk or vice-versa, are also known as the **Markowitz efficient set**. \n",
    "\n",
    "Given the efficient set, generated for the $k$-portfolio of Dow stocks discussed in Sec. 5.3, the following Python code traces the efficient frontier using **matplotlib** library."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Graph Efficient Frontier\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "NoPoints = riskPoint.size\n",
    "\n",
    "colours = \"blue\"\n",
    "area = np.pi*3\n",
    "\n",
    "plt.title('Efficient Frontier for k-portfolio 1 of Dow stocks')\n",
    "plt.xlabel('Annualized Risk(%)')\n",
    "plt.ylabel('Annualized Expected Portfolio Return(%)' )\n",
    "plt.scatter(riskPoint, retPoint, s=area, c=colours, alpha =0.5)\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The efficient frontier for a portfolio serves to provide a road-map for the choices that investors can make,  based on their risk appetites.  \n",
    "  \n",
    "For a specific annualized risk (x%) or a range of values desired by the investor,  the corresponding annualized expected portfolio return (y%) or a range of return values or vice-versa,  can be easily obtained by a visual inspection of the graph.   The point(s) of intersection on the efficient frontier which represent(s) the optimal portfolios,  can be easily decoded to arrive at the optimal weights which determine the optimal allocations of capital to the assets in the portfolio, corresponding to the choice of risk or return.   \n",
    "\n",
    "Fig. 5.1 illustrates how an efficient frontier can direct a risk-seeking investor who desires an annualized expected return of 20%,  to invest in a portfolio that holds a 14% annualized risk, while enlightening the investor on the optimal weights which will ensure the aspired risk/return.  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson5Fig5_1.png)\n",
    "#### Fig. 5.1 Usefulness of efficient frontiers to investors - an illustration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.5  Efficient Frontiers: $k$-portfolios vs \"Ideal\" portfolio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Lesson 3 Heuristic Portfolio Selection** discussed three different selections of $k$-portfolios comprising Dow stocks. Labelled as $k$-portfolio 1, 2 and 3, the behaviour of these portfolios were compared with  that of an \"ideal\" portfolio where the investor decides to invest in all the stocks of the \"mini-universe\". The observations discussed in Sec. 4.4 of **Lesson 4 Traditional Methods for Portfolio Construction** showed that $k$-portfolios were endowed with merits that rendered them advantageous to the investors.   \n",
    "  \n",
    " In this lesson, we investigate the  risk-return trade-off behaviour of the $k$-portfolios, by tracing their efficient frontiers and comparing the same with that of the  \"ideal\" portfolio. The Mean-Variance Optimization model was applied over all the portfolios. Fig. 5.2 illustrates the efficient frontiers traced for $k$-portfolio 1, $k$-portfolio 2, $k$-portfolio 3 and the \"ideal\" portfolio, over the DJIA Index data set (April 2014 - April 2019).  \n",
    "   \n",
    "The CSV files DJIA_Apr112014_Apr112019_kpf1.csv, DJIA_Apr112014_Apr112019_kpf2.csv, DJIA_Apr112014_Apr112019_kpf3.csv hold the datasets for the respective $k$-portfolios 1,2 and 3, and DJIA_Apr112014_Apr112019.csv, the dataset for the Dow \"mini-universe\".     \n",
    "   \n",
    " The proximity of the $k$-portfolio efficient frontiers to that of the \"ideal\" portfolio reveals the similarity of  risk-return trade-off behaviour of the $k$-portfolios,  to that of the \"ideal\" portfolio. The proximity of the $k$-portfolio efficient frontiers to one another, also reveals the similarity of their portfolio behaviour despite holding different sets of assets that were randomly selected, one  from each of the clusters, during their construction. (Refer Sec 3.4 of  **Lesson 3 Heuristic Portfolio Selection** for the construction of $k$-portfolios of Dow stocks)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](DJIAkpfsIdeal_EfficientFrontiersComparison.png)\n",
    "#### Fig. 5.2 Performance Comparison of efficient frontiers of $k$-portfolios with the \"ideal\" efficient frontier,  for DJIA Index (April 2014-Aprl 2019)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The efficient frontiers traced by the Mean-Variance Optimization model or known as the Markowitz model,  are termed as “exact” or “ideal” in the literature. The Markowitz model merely deals with basic constraints imposed over a bi-criterion objective function. The model can be easily solved using a variety of traditional methods including the one discussed in this lesson.  \n",
    "\n",
    "In reality, portfolio optimization problem models can turn too complex for direct solving by traditional methods. Thus when constraints reflective of investor preferences or  investment strategies or  market norms or religious laws etc.,  are included,  the problem models can turn complex,  warranting the need to look for non-traditional, nature-inspired  methods, referred to as **metaheuristics** in recent literature, to arrive at acceptable if not accurate solutions.  In the face of these models, a Markowitz model is often dubbed as an “Unconstrained Optimization” problem for it can be easily solved with the simplest of the traditional techniques."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Companion Reading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  \n",
    "\n",
    "This blog  is an abridged adaptation of concepts discussed in Chapter 1 and Chapter 3 of [PAI 18] to Dow Jones dataset (DJIA index: April, 2014- April, 2019) and implemented in Python. Readers (read \"worker bees\"),  seeking more information may refer to the corresponding chapter in the  book.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3 align=\"left\">References</h3>   \n",
    "\n",
    "[MAR 52]   Markowitz H., Portfolio Selection, *The Journal of Finance*, vol. 7, no. 1, \n",
    "           pp. 77-91, Mar., 1952.  \n",
    "  \n",
    "  \n",
    "[PAI 18]   Vijayalakshmi Pai G. A., Metaheuristics for Portfolio Optimization- *An Introduction using MATLAB*, Wiley-ISTE, 2018. https://www.mathworks.com/academia/books/metaheuristics-for-portfolio-optimization-pai.html  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Next.....Lesson 6: Sharpe Ratio based Portfolio Optimization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson5ExitTailImage.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
